
#include <BGridLayout>
#include <BVBoxLayout>
#include <BHBoxLayout>
#include <BStyle>

#include "GeometryPanel.h"

GeometryPanel::GeometryPanel(BWidget* parent) : BGroupBox(parent)
{
	this->setTitle("Geometry");

	BHBoxLayout* topLayout = new BHBoxLayout();
	{
		_optimizedCheckBox = new BCheckBox("optimized");
		_normalSmoothButton = new BButton("smooth");
		_normalSmoothButton->setForm(Form_IconAlone);
		_facesReverseButton = new BButton("reverse");
		_facesReverseButton->setForm(Form_IconAlone);
		_edgeMergeButton = new BButton("edge-merge");
		_edgeMergeButton->setForm(Form_IconAlone);
		topLayout->addWidget(_optimizedCheckBox);
		topLayout->addWidget(_normalSmoothButton, 0);
		topLayout->addWidget(_facesReverseButton, 0);
		topLayout->addWidget(_edgeMergeButton, 0);
	}

	BGridLayout* gridLayout = new BGridLayout();
	{
		_vertexCountLabel = new BLabel();
		_normalCountLabel = new BLabel();
		_colorCountLabel = new BLabel();
		_texCoordCountLabel = new BLabel();

		gridLayout->addWidget(1, 0, new BLabel("vertex"));
		gridLayout->addWidget(1, 1, _vertexCountLabel);
		gridLayout->addWidget(2, 0, new BLabel("normal"));
		gridLayout->addWidget(2, 1, _normalCountLabel);
		gridLayout->addWidget(3, 0, new BLabel("color"));
		gridLayout->addWidget(3, 1, _colorCountLabel);
		gridLayout->addWidget(4, 0, new BLabel("tex-coord"));
		gridLayout->addWidget(4, 1, _texCoordCountLabel);
		gridLayout->setColumnStretch(0, 0);
	}

	BLabel* elementsLabel = new BLabel("elements");
	_elementTableWidget = new BTableWidget();
	_elementTableWidget->setColumnCount(5);
	_elementTableWidget->setColumnLabel(0, "Name");
	_elementTableWidget->setColumnLabel(1, "Primitive");
	_elementTableWidget->setColumnLabel(2, "Indices");
	_elementTableWidget->setColumnLabel(3, "Pieces");
	_elementTableWidget->setColumnPolicy(Policy_Preferred | Policy_Expanding);
	_elementTableWidget->setAreaPolicy(Policy_Expanding);
	_elementTableWidget->setSelectMode(Select_Single | Select_Rows);

	_elementNameEdit = new BLineEdit(_elementTableWidget);
	_elementNameEdit->hide();

	BVBoxLayout* vlayout = new BVBoxLayout(this);
	vlayout->addLayout(topLayout);
	vlayout->addLayout(gridLayout);
	vlayout->addWidget(elementsLabel);
	vlayout->addWidget(_elementTableWidget);

	connect(this, Signal_AssetChanged, &GeometryPanel::slotAssetChanged);
	connect(_optimizedCheckBox, Signal_Toggled, &GeometryPanel::slotOptimizedToggled);
	connect(_normalSmoothButton, Signal_Clicked, &GeometryPanel::slotNormalSmoothButtonClicked);
	connect(_facesReverseButton, Signal_Clicked, &GeometryPanel::slotFacesReverseButtonClicked);
	connect(_elementTableWidget, Signal_ItemClicked, &GeometryPanel::slotElementTableItemClicked);
	connect(_elementNameEdit, Signal_EditFinished, &GeometryPanel::slotElementNameEditFinished);
	connect(_elementNameEdit, Signal_Focused, &GeometryPanel::slotElementNameEditFocused);
}
GeometryPanel::~GeometryPanel()
{

}

const char* GeometryPanel::primitiveName(Primitive primitive)
{
	switch (primitive)
	{
	case BWE::Primitive_None:
		return "None";
	case BWE::Primitive_Points:
		return "Points";
	case BWE::Primitive_Lines:
		return "Lines";
	case BWE::Primitive_LineStrip:
		return "LineStrip";
	case BWE::Primitive_LineLoop:
		return "LineLoop";
	case BWE::Primitive_Triangles:
		return "Triangles";
	case BWE::Primitive_TriangleStrip:
		return "TriangleStrip";
	case BWE::Primitive_TriangleFan:
		return "TriangleFan";
	case BWE::Primitive_Quads:
		return "Quads";
	case BWE::Primitive_QuadStrip:
		return "QuadStrip";
	case BWE::Primitive_Polygon:
		return "Polygon";
	default:
		return 0;
	}
}

void GeometryPanel::slotAssetChanged(BObject* object, const BValue& value)
{
	BGeometry* geometry = value;
	if (_geometry != geometry)
	{
		if (_geometry)
		{
			disconnect(_geometry);
			_optimizedCheckBox->setChecked(false);
			_vertexCountLabel->setText(BString());
			_normalCountLabel->setText(BString());
			_colorCountLabel->setText(BString());
			_texCoordCountLabel->setText(BString());
			_elementTableWidget->clearItems();
		}
		_geometry = geometry;
		if (_geometry)
		{
			connect(_geometry, Signal_Attached, &GeometryPanel::slotGeometryAttached);
			connect(_geometry, Signal_Detached, &GeometryPanel::slotGeometryDetached);
			_optimizedCheckBox->setChecked(_geometry->optimized());
			if (const BVectorArray* vertices = _geometry->vertices())
				_vertexCountLabel->setText(vertices->size());
			if (const BVectorArray* normals = _geometry->normals())
				_normalCountLabel->setText(normals->size());
			if (const BColorArray* colors = _geometry->colors())
				_colorCountLabel->setText(colors->size());
			if (const BCoordArray* coords = _geometry->texCoords())
				_texCoordCountLabel->setText(coords->size());
			_elementTableWidget->setRowCount(_geometry->elementCount());
			for (int i = 0; i < _geometry->elementCount(); i++)
			{
				BElement* element = _geometry->element(i);
				_elementTableWidget->setRowAsset(i, element);
				_elementTableWidget->setRowLabel(i, BString(i));
				_elementTableWidget->addItem(i, 0, element->name());
				_elementTableWidget->addItem(i, 1, primitiveName(element->primitive()));
				if (const BIntArray* indices = element->indices())
					_elementTableWidget->addItem(i, 2, BString(indices->size()));
				else
					_elementTableWidget->addItem(i, 2, BString());
				if (BPieceArray* pieces = element->pieces())
					_elementTableWidget->addItem(i, 3, BString(pieces->size()));
				else
					_elementTableWidget->addItem(i, 3, BString());
			}
		}
	}
}
void GeometryPanel::slotOptimizedToggled(BObject* object, const BValue& value)
{
	bool checked = value;
	_geometry->setOptimized(checked);
}
void GeometryPanel::slotNormalSmoothButtonClicked(BObject* object, const BValue& value)
{
	_geometry->smooth();
}
void GeometryPanel::slotFacesReverseButtonClicked(BObject* object, const BValue& value)
{
	_geometry->reverse();
}
void GeometryPanel::slotElementTableItemClicked(BObject* object, const BValue& value)
{
	if (BTableItem* item = value)
	{
		if (_elementNameEdit->asset() != item)
		{
			_elementNameEdit->setAsset(item);
		}
		else
		{
			_elementNameEdit->setRect(item->rect());
			_elementNameEdit->setText(item->text());
			_elementNameEdit->popup();
		}
	}
}
void GeometryPanel::slotElementNameEditFinished(BObject* object, const BValue& value)
{
	if (BTableItem* item = _elementNameEdit->asset())
	{
		BElement* element = _elementTableWidget->rowAsset(item->row());
		element->setName(_elementNameEdit->text());
		item->setText(_elementNameEdit->text());
		_elementNameEdit->hide();
	}
}
void GeometryPanel::slotElementNameEditFocused(BObject* object, const BValue& value)
{
	bool focused = value;
	if (!focused)
	{
		_elementNameEdit->setAsset(BValue());
		_elementNameEdit->setText(BString());
		_elementNameEdit->hide();
	}
}
void GeometryPanel::slotGeometryAttached(BObject* object, const BValue& value)
{
	if (BElement* element = value)
	{
		int row = _elementTableWidget->addRows(1);
		_elementTableWidget->setRowAsset(row, element);
		_elementTableWidget->setRowLabel(row, BString(row));
		_elementTableWidget->addItem(row, 0, element->name());
		_elementTableWidget->addItem(row, 1, primitiveName(element->primitive()));
		if (const BIntArray* indices = element->indices())
			_elementTableWidget->addItem(row, 2, BString(indices->size()));
		else
			_elementTableWidget->addItem(row, 2, BString());
		if (BPieceArray* pieces = element->pieces())
			_elementTableWidget->addItem(row, 3, BString(pieces->size()));
		else
			_elementTableWidget->addItem(row, 3, BString());
	}
}
void GeometryPanel::slotGeometryDetached(BObject* object, const BValue& value)
{
	if (BElement* element = value)
	{
		int row = _elementTableWidget->rowOfAsset(element);
		_elementTableWidget->removeRow(row);
	}
}

void GeometryPanel::styleEvent(const BEvent& event)
{
	BGroupBox::styleEvent(event);
	const BStyle* style = event.value();
	_normalSmoothButton->setIcon(style->icon("normal-smooth"));
	_facesReverseButton->setIcon(style->icon("faces-reverse"));
	_edgeMergeButton->setIcon(style->icon("edge-merge"));

	_normalSmoothButton->setTips(style->text("tips-normal-smooth"));
	_facesReverseButton->setTips(style->text("tips-faces-reverse"));
	_edgeMergeButton->setTips(style->text("tips-edge-merge"));
}
